

#include <string.h>
#include <trace.h>
#include <tts.h>
#include <gap.h>


T_SERVER_ID tts_service_id;

static P_FUN_SERVER_GENERAL_CB pfn_tts_service_cb = NULL; 
static const uint8_t GATT_UUID_TTS_SERVICE[16] = 
{
    0xab, 0x62, 0xec, 0x32, 0x2e, 0x3d, 0x8a, 0x8e, 0x53, 0x42, 0x51, 0xe7, 0x01, 0x00, 0xe3, 0xf5
};

const T_ATTRIB_APPL tts_service_tbl[] = 
{
    /* << Primary Service >>, .. */
    {
        (ATTRIB_FLAG_VOID | ATTRIB_FLAG_LE ), /*flags */
        {
            LO_WORD( GATT_UUID_PRIMARY_SERVICE ),
            HI_WORD( GATT_UUID_PRIMARY_SERVICE ),
        },
        UUID_128BIT_SIZE,
        (void*)GATT_UUID_TTS_SERVICE,
        GATT_PERM_READ,
    },
    
    // characteristic charateristic
    {
        ATTRIB_FLAG_VALUE_INCL,
        {
            LO_WORD( GATT_UUID_CHARACTERISTIC ),
            HI_WORD( GATT_UUID_CHARACTERISTIC ),
            GATT_CHAR_PROP_WRITE_NO_RSP | GATT_CHAR_PROP_NOTIFY,
        },
        1,
        NULL,
        GATT_PERM_READ,
    },
    {
        ATTRIB_FLAG_VALUE_APPL | ATTRIB_FLAG_UUID_128BIT , // UUID
        {
            TTS_CHAR_VAL_UUID
//            LO_WORD( TTS_CHAR_VAL_UUID ),
//            HI_WORD( TTS_CHAR_VAL_UUID ),
        },
        0,
        NULL,
        GATT_PERM_READ | GATT_PERM_WRITE
    },
    {
        ATTRIB_FLAG_VALUE_INCL | ATTRIB_FLAG_CCCD_APPL, // cccd 
        {
            LO_WORD( GATT_UUID_CHAR_CLIENT_CONFIG ),
            HI_WORD( GATT_UUID_CHAR_CLIENT_CONFIG ),
            
            LO_WORD( GATT_CLIENT_CHAR_CONFIG_DEFAULT ),
            HI_WORD( GATT_CLIENT_CHAR_CONFIG_DEFAULT )
        },
        2,
        NULL,
        (GATT_PERM_READ | GATT_PERM_WRITE ),
    },
    
    // Rx
    {
        ATTRIB_FLAG_VALUE_INCL,
        {
            LO_WORD( GATT_UUID_CHARACTERISTIC ),
            HI_WORD( GATT_UUID_CHARACTERISTIC ),
            GATT_CHAR_PROP_WRITE_NO_RSP ,
        },
        1,
        NULL,
        GATT_PERM_READ,
    },
    {
        ATTRIB_FLAG_VALUE_APPL | ATTRIB_FLAG_UUID_128BIT, // UUID
        {
            TTS_CHAR_RX_UUID
//            LO_WORD( TTS_CHAR_RX_UUID ),
//            HI_WORD( TTS_CHAR_RX_UUID ),
        },
        0,
        NULL,
        GATT_PERM_WRITE
    },
    // Tx
    {
        ATTRIB_FLAG_VALUE_INCL,
        {
            LO_WORD( GATT_UUID_CHARACTERISTIC ),
            HI_WORD( GATT_UUID_CHARACTERISTIC ),
            GATT_CHAR_PROP_NOTIFY ,
        },
        1,
        NULL,
        GATT_PERM_READ,
    },
    {
        ATTRIB_FLAG_VALUE_APPL | ATTRIB_FLAG_UUID_128BIT, // UUID
        {
            TTS_CHAR_TX_UUID
//            LO_WORD( TTS_CHAR_TX_UUID ),
//            HI_WORD( TTS_CHAR_TX_UUID ),
        },
        0,
        NULL,
        GATT_PERM_READ
    },
    {
        ATTRIB_FLAG_VALUE_INCL | ATTRIB_FLAG_CCCD_APPL, // cccd 
        {
            LO_WORD( GATT_UUID_CHAR_CLIENT_CONFIG ),
            HI_WORD( GATT_UUID_CHAR_CLIENT_CONFIG ),
            
            LO_WORD( GATT_CLIENT_CHAR_CONFIG_DEFAULT ),
            HI_WORD( GATT_CLIENT_CHAR_CONFIG_DEFAULT )
        },
        2,
        NULL,
        (GATT_PERM_READ | GATT_PERM_WRITE ),
    }
    
};

T_APP_RESULT tts_svc_attr_write_cb( uint8_t conn_id,
                                    uint8_t service_id, 
                                    uint16_t atrrib_index,
                                    T_WRITE_TYPE write_type,
                                    uint16_t length,
                                    uint8_t *p_value,
                                    P_FUN_WRITE_IND_POST_PROC * p_write_ind_post_proc
)
{
    bool handle = true; 
    
    T_TTS_CALLBACK_DATA callback_data;
    T_APP_RESULT cause = APP_RESULT_SUCCESS;
    
    switch( atrrib_index )
    {
        case TTS_SERVICE_CHAR_VAL_WRITE_IDX:
            callback_data.msg_type = SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE;
            callback_data.msg_data.write.write_type = TTS_WRITE_VAL;
            callback_data.msg_data.write.len = length;
            callback_data.msg_data.write.p_value = p_value;
            break;
        case TTS_SERVICE_CHAR_RX_WRITE_IDX:
            callback_data.msg_type = SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE;
            callback_data.msg_data.write.write_type = TTS_WRITE_RX;
            callback_data.msg_data.write.len = length;
            callback_data.msg_data.write.p_value = p_value;
            break;
        default:
            handle = false; 
            cause = APP_RESULT_ATTR_NOT_FOUND;
            break;
    }
    
    if( ( pfn_tts_service_cb ) && (handle == true ) )
    {
        pfn_tts_service_cb( service_id, (void*)&callback_data ); 
    }
    
    return cause; 
}

void tts_svc_cccd_update_cb(
                            uint8_t conn_id,
                            T_SERVER_ID service_id,
                            uint16_t index, 
                            uint16_t cccd_bits)
{
    bool handle = true;
    
    T_TTS_CALLBACK_DATA callback_data;
    callback_data.msg_type = SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION;
    
    switch( index ) 
    {
        case TTS_SERVICE_CHAR_VAL_CCCD_IDX:
            if( cccd_bits & GATT_CLIENT_CHAR_CONFIG_NOTIFY ) 
            {
                callback_data.msg_type = SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION;
                callback_data.msg_data.notification_index = TTS_NOTIFY_VAL_ENABLE;
            }
            else 
            {
                callback_data.msg_type = SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION;
                callback_data.msg_data.notification_index = TTS_NOTIFY_VAL_DISABLE;
            }
            break;
        
        case TTS_SERVICE_CHAR_TX_NOTIFY_CCCD_IDX:
            if( cccd_bits & GATT_CLIENT_CHAR_CONFIG_NOTIFY ) 
            {
                callback_data.msg_type = SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION;
                callback_data.msg_data.notification_index = TTS_NOTIFY_TX_ENABLE;
            }
            else 
            {
                callback_data.msg_type = SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION;
                callback_data.msg_data.notification_index = TTS_NOTIFY_TX_DISABLE;
            }
            break;
        default:
            handle = false;
            break;
    }
    
    if( pfn_tts_service_cb && (handle == true) ) 
    {
        pfn_tts_service_cb( service_id, (void*)&callback_data ); 
    }    
}

bool tts_send_val_data( uint8_t conn_id, T_SERVER_ID service_id, void *p_value, uint16_t length)
{
    return server_send_data( 
                            conn_id, 
                            service_id, 
                            TTS_SERVICE_CHAR_VAL_WRITE_IDX, 
                            p_value, 
                            length, 
                            GATT_PDU_TYPE_ANY 
                            ); 
}
bool tts_send_tx_data( uint8_t conn_id, T_SERVER_ID service_id, void *p_value, uint16_t length)
{
    return server_send_data( conn_id, 
                            service_id, 
                            TTS_SERVICE_CHAR_TX_NOITFY_IDX, 
                            p_value, 
                            length, 
                            GATT_PDU_TYPE_ANY );
}

const T_FUN_GATT_SERVICE_CBS tts_svc_cbs = 
{
    NULL,
    tts_svc_attr_write_cb,
    tts_svc_cccd_update_cb
};

uint8_t tts_svc_add_service(void *p_func)
{
    uint8_t service_id;
    if( false == server_add_service( &service_id,
                                    (uint8_t*)tts_service_tbl,
                                    sizeof( tts_service_tbl ),
                                    tts_svc_cbs) 
    )
    {
        service_id = 0xff;
        return service_id;
    }
    
    pfn_tts_service_cb = (P_FUN_SERVER_GENERAL_CB)p_func;
    return service_id; 
}

